using LiJ.Common.Core;
using LiJ.Common.Encrypt;
using LiJ.Common.Plugs.LogPlug;
using LiJ.Http.Extention;
using LiJ.Http.Mos;
using LiJ.Pay.WeiXin.SysTools;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace LiJ.Pay.WeiXin
{
	/// <summary>
	///  微信支付基类
	/// </summary>
	public abstract class WxPayBaseApi : BaseConfigProvider<WxPayCenterConfig, WxPayBaseApi>
	{
		/// <summary>
		/// 微信api接口地址
		/// </summary>
		protected const string m_ApiUrl = "https://api.mch.weixin.qq.com";

		private HttpClient _client;

		/// <summary>
		/// 构造函数
		/// </summary>
		/// <param name="config"></param>
		protected WxPayBaseApi(WxPayCenterConfig config)
			: base(config)
		{
			base.ModuleName = WxPayConfigProvider.ModuleName;
		}

		/// <summary>
		/// 处理远程请求方法，并返回需要的实体
		/// </summary>
		/// <typeparam name="T">需要返回的实体类型</typeparam>
		/// <param name="request">远程请求组件的request基本信息</param>
		/// <param name="funcFormat">获取实体格式化方法</param>
		/// <param name="client">自定义请求客户端，当前主要是因为标准库没有提供证书设置选项，所以通过上层运行时传入设置委托，在使用证书的子类中构造客户端传入 </param>
		/// <returns>实体类型</returns>
		protected async Task<T> RestCommonAsync<T>(LHttpRequest request, Func<HttpResponseMessage, Task<T>> funcFormat = null, HttpClient client = null) where T : WxPayBaseResp, new()
		{
			T t = null;
			try
			{
				HttpResponseMessage resp = await request.RestSend(client);
				if (resp.IsSuccessStatusCode)
				{
					t = ((funcFormat == null) ? this.GetRespResult<T>(await resp.Content.ReadAsStringAsync()) : (await funcFormat(resp)));
				}
			}
			catch (Exception ex)
			{
				string str = LogUtil.Error("基类请求出错，错误信息：" + ex.Message, "RestCommon", "pay_center");
				T val = new T();
				val.Ret = -1;
				val.Msg = "当前请求出错，错误码：" + str;
				t = val;
			}
			if (t != null && ((ResultMo)(object)t).IsSuccess())
			{
				if (t.return_code.ToUpper() == "SUCCESS" && t.result_code.ToUpper() == "SUCCESS")
				{
					return t;
				}
				t.Ret = -1;
				t.Msg = t.return_msg + t.err_code_des;
				return t;
			}
			object val2 = t;
			if (val2 == null)
			{
				val2 = new T();
				((T)val2).Ret = 1404;
				((T)val2).Msg = "未发现结果信息！";
			}
			return (T)val2;
		}

		/// <summary>
		/// 获取响应结果
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="contentStr"></param>
		/// <returns></returns>
		protected T GetRespResult<T>(string contentStr) where T : WxPayBaseResp, new()
		{
			XmlDocument respXml = null;
			SortedDictionary<string, object> sortedDictionary = SysUtil.ChangXmlToDir(contentStr, ref respXml);
			if (!sortedDictionary.ContainsKey("sign"))
			{
				T val = new T();
				val.Ret = 1301;
				val.Msg = "当前结果签名信息不存在！";
				return val;
			}
			T val2 = new T();
			val2.RespXml = respXml;
			T val3 = val2;
			val3.FromResContent(sortedDictionary);
			if (this.GetSign(WxPayBaseApi.GetSignContent(sortedDictionary)) == val3.sign)
			{
				return val3;
			}
			val3.Ret = 1301;
			val3.Msg = "返回的结果签名（sign）不匹配";
			return val3;
		}

		/// <summary>
		///   post 支付接口相关请求
		/// </summary>
		/// <typeparam name="T">返回参数类型</typeparam>
		/// <param name="addressUrl">接口地址</param>
		/// <param name="xmlDirs">请求参数的排序字典（不包括：appid,mch_id,sign。 会自动补充）</param>
		/// <param name="funcFormat"></param>
		/// <param name="client">自定义请求客户端，当前主要是因为标准库没有提供证书设置选项，所以通过上层运行时传入设置委托，在使用证书的子类中构造客户端传入</param>
		/// <param name="dirformat">生成签名后对字典发送前的操作，例如urlencode操作</param>
		/// <returns></returns>
		protected async Task<T> PostApiAsync<T>(string addressUrl, SortedDictionary<string, object> xmlDirs, Func<HttpResponseMessage, Task<T>> funcFormat = null, HttpClient client = null, Action<SortedDictionary<string, object>> dirformat = null) where T : WxPayBaseResp, new()
		{
			xmlDirs.Add("appid", (object)base.ApiConfig.AppId);
			xmlDirs.Add("mch_id", (object)base.ApiConfig.MchId);
			this.CompleteDicSign(xmlDirs);
		    dirformat?.Invoke(xmlDirs);
		    LHttpRequest request = new LHttpRequest
			{
				HttpMothed = HttpMothed.Post,
				AddressUrl = addressUrl,
				CustomBody = xmlDirs.ProduceXml()
			};
			return await this.RestCommonAsync<T>(request, funcFormat, client);
		}

		/// <summary>
		///  补充完善 字典sign签名
		///     因为AppId的参数名称在不同接口中不同，所以不放在这里补充
		/// </summary>
		protected internal void CompleteDicSign(SortedDictionary<string, object> xmlDirs)
		{
			if (!string.IsNullOrEmpty(base.ApiConfig.sub_mch_id))
			{
				if (!string.IsNullOrEmpty(base.ApiConfig.sub_appid))
				{
					xmlDirs.Add("sub_appid", base.ApiConfig.sub_appid);
				}
				xmlDirs.Add("sub_mch_id", base.ApiConfig.sub_mch_id);
			}
			string signContent = WxPayBaseApi.GetSignContent(xmlDirs);
			string sign = this.GetSign(signContent);
			xmlDirs.Add("sign", sign);
		}

		/// <summary> 生成签名,统一方法 </summary>
		/// <param name="encStr">不含key的参与签名串</param>
		/// <returns></returns>
		protected string GetSign(string encStr)
		{
			return Md5.EncryptHexString(encStr + "&key=" + base.ApiConfig.Key, null).ToUpper();
		}

		/// <summary> 获取签名内容字符串</summary>
		protected static string GetSignContent(SortedDictionary<string, object> xmlDirs)
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (KeyValuePair<string, object> xmlDir in xmlDirs)
			{
				object value = xmlDir.Value;
				string value2 = value?.ToString();
				if (xmlDir.Key != "sign" && !string.IsNullOrEmpty(value2))
				{
					stringBuilder.Append(xmlDir.Key).Append("=").Append(value2)
						.Append("&");
				}
			}
			return stringBuilder.ToString().TrimEnd(new char[1]
			{
				'&'
			});
		}

		/// <summary>   接受微信支付通知后需要返回的信息 </summary>
		public string GetCallBackReturnXml(ResultMo res)
		{
			return string.Format(string.Format("<xml><return_code><![CDATA[{0}]]></return_code><return_msg><![CDATA[{1}]]></return_msg></xml>", res.IsSuccess() ? "SUCCESS" : "FAIL", res.Msg), Array.Empty<object>());
		}

		/// <summary>
		///   获取设置了证书的HttpClient
		///     如果是上下文配置模式，则每次都返回新值
		/// </summary>
		/// <returns></returns>
		protected internal HttpClient GetCertHttpClient()
		{
			if (base.ConfigMode != ConfigProviderMode.Context && this._client != null)
			{
				return this._client;
			}
			HttpClientHandler httpClientHandler = new HttpClientHandler
			{
				ServerCertificateCustomValidationCallback = ((HttpRequestMessage msg, X509Certificate2 c, X509Chain chain, SslPolicyErrors sslErrors) => sslErrors == SslPolicyErrors.None)
			};
			X509Certificate2 value = new X509Certificate2(base.ApiConfig.CertPath, base.ApiConfig.CertPassword);
			httpClientHandler.ClientCertificates.Add(value);
			if (base.ConfigMode == ConfigProviderMode.Context)
			{
				return new HttpClient(httpClientHandler);
			}
			return this._client = new HttpClient(httpClientHandler);
		}

		/// <inheritdoc />
		protected override WxPayCenterConfig GetDefaultConfig()
		{
			return WxPayConfigProvider.DefaultConfig;
		}
	}
}
